﻿using CPAIS.Model;
using CPAIS.Updater;
using System;
using System.Xml;

namespace CPAIS.LogParser.PluginsWithXmlReader
{
    /// <summary>
    /// Log parser for parsing event log file with XML Root TAG 'WorkflowLog', like:
    /// 
    /// <?xml version="1.0" encoding="UTF-8"?>
    /// <WorkflowLog description="A simple example about the bronchial lung cancer">
    ///     <ProcessInstance id="406287" description="肺癌">
    ///         <Data>
    ///             <Attribute name="Gender">男</Attribute>
    ///             <Attribute name="Birthday">1951-01-01 00:00:00.0</Attribute>
    ///             <Attribute name="Care_Level">2</Attribute>
    ///         </Data>
    ///         <AuditTrailEntry>
    ///             <WorkflowModelElement>Admission</WorkflowModelElement>
    ///             <EventType>complete</EventType>
    ///             <Timestamp>2008-09-01T14:03:00.000+08:00</Timestamp>
    ///         </AuditTrailEntry>
    ///     </ProcessInstance>
    /// </WorkflowLog>
    /// 
    /// OR
    /// 
    /// <?xml version="1.0" encoding="UTF-8"?>
    /// <WorkflowLog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://is.tm.tue.nl/research/processmining/WorkflowLog.xsd" description="Patient trace repository">
    ///     <ProcessInstance id="410770" description="Breast cancer">
    ///         <Data>
    ///             <Attribute name="Care Level">2</Attribute>
    ///             <Attribute name="Department">七病区</Attribute>
    ///             <Attribute name="Patient_Birthday">Oct 22 1958 12:00AM</Attribute>
    ///             <Attribute name="Patient_Gender">女</Attribute>
    ///         </Data>
    ///         <AuditTrailEntry>
    ///             <WorkflowModelElement>Admission</WorkflowModelElement>
    ///             <EventType>complete</EventType>
    ///             <Timestamp>2008-10-20T17:29:00.000+08:00</Timestamp>
    ///         </AuditTrailEntry>
    ///     </ProcessInstance>
    /// </WorkflowLog>
    /// 
    /// </summary>
    public class LogParserC : ILogParserWithXmlReader
    {
        #region String used for parsing XML file
        private const string EventLog = "WorkflowLog";
        private const string Description = "description";
        private const string ProcessInstance = "ProcessInstance";
        private const string ID = "id";
        private const string Data = "Data";
        private const string Attribute = "Attribute";
        private const string Name = "name";
        private const string Gender = "Gender";
        private const string Patient_Gender = "Patient_Gender";
        private const string Birthday = "Birthday";
        private const string Patient_Birthday = "Patient_Birthday";
        private const string Department = "Department";
        private const string AuditTrailEntry = "AuditTrailEntry";
        private const string WorkflowModelElement = "WorkflowModelElement";
        private const string EventType = "EventType";
        private const string Timestamp = "Timestamp";
        private const string Complete = "complete";
        private const string Admission = "Admission";
        private const string Discharge = "Discharge";

        private const string Male = "男";
        private const string Female = "女";
        #endregion

        public void Parse(LogModel logModel, XmlReader reader, StateUpdater updater)
        {
            while (reader.Read())
            {
                #region Depth 1
                if (reader.Depth < 1)
                    break;
                else if (reader.Depth == 1 && reader.NodeType == XmlNodeType.Element && reader.Name == ProcessInstance)
                {
                    #region Read Attributes

                    string
                        strPid = "",
                        strDescription = "";

                    while (reader.MoveToNextAttribute())
                    {
                        switch (reader.Name)
                        {
                            case ID:
                                strPid = reader.ReadContentAsString().Trim();
                                break;
                            case Description:
                                strDescription = reader.ReadContentAsString().Trim();
                                break;
                        }
                    }
                    Trace trace = new Trace(logModel, strPid);
                    trace.AddDiagnosis(strDescription);

                    #endregion

                    while (reader.Read())
                    {
                        #region Depth 2
                        if (reader.Depth < 2)
                            break;
                        else if (reader.Depth == 2 && reader.NodeType == XmlNodeType.Element)
                        {
                            if (reader.Name == Data)
                            {
                                while (reader.Read())
                                {
                                    #region Depth 3
                                    if (reader.Depth < 3)
                                        break;
                                    else if (reader.Depth == 3 && reader.NodeType == XmlNodeType.Element && reader.Name == Attribute)
                                    {
                                        reader.MoveToFirstAttribute();
                                        string strKey = reader.Value.Trim();
                                        reader.MoveToElement();
                                        string strValue = reader.ReadElementContentAsString().Trim();
                                        switch (strKey)
                                        {
                                            case Patient_Gender:
                                            case Gender:
                                                trace.Sex = strValue == Male ? SexType.Male : (strValue == Female ? SexType.Female : SexType.Unknown);
                                                break;
                                            case Patient_Birthday:
                                            case Birthday:
                                                trace.Birthday = DateTime.Parse(strValue);
                                                break;
                                            case Department:
                                                trace.Department = strValue;
                                                break;
                                        }
                                    }
                                    #endregion
                                }
                            }
                            else if (reader.Name == AuditTrailEntry)
                            {
                                string strType = "";
                                string strState = "";
                                DateTime timestamp = new DateTime();

                                while (reader.Read())
                                {
                                    #region Depth 3
                                    if (reader.Depth < 3)
                                        break;
                                    else if (reader.Depth == 3 && reader.NodeType == XmlNodeType.Element)
                                    {
                                        if (reader.Name == WorkflowModelElement)
                                        {
                                            strType = reader.ReadElementContentAsString().Trim();
                                        }
                                        else if (reader.Name == EventType)
                                        {
                                            strState = reader.ReadElementContentAsString().Trim();
                                        }
                                        else if (reader.Name == Timestamp)
                                        {
                                            timestamp = DateTime.Parse(reader.ReadElementContentAsString());
                                        }
                                    }
                                    #endregion
                                }

                                if (strState == Complete)
                                {
                                    if (strType == Admission)
                                        trace.Admit = timestamp;
                                    else if (strType == Discharge)
                                        trace.Discharge = timestamp;

                                    ActionEvent entry = new ActionEvent(trace, timestamp, strType);
                                    trace.AddAction(entry);
                                }
                            }
                        }
                        #endregion
                    }
                    trace.OrderTrace();
                    logModel.AddTrace(trace);
                    if (updater != null)
                        updater.UpdateMessage(string.Format("{0} traces have been loaded...", logModel.TraceCount));
                }
                #endregion                
            }
        }

        public string XmlTag
        {
            get { return EventLog; }
        }
    }
}
